﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Linq.Expressions;
using System.Reflection;
using System.Diagnostics;
using Extensions;
using System.Text.RegularExpressions;
using System.Windows.Data;
using System.ComponentModel;
using Dynamite;
using Dynamite.Extensions;
using Dynamite.Data.Extensions;
using System.Collections;
using System.Data;
 
namespace DynamiteTester
{
    /// <summary>
    /// Interactive console test program for Dynamite dynamic sorting library
    /// </summary>
    class Program
    {
        public struct Point //: IComparable
        {
            public int X { get; set; }
            public int Y { get; set; }
            public int? Height { get; set; }
            public Person Owner { get; set; }

            #region IComparable Members

            public int CompareTo(object obj)
            {
                if (obj == null) return -1;

                Point otherPoint = (Point)obj;
                return X.CompareTo(otherPoint.X);
            }

            #endregion

            public override string ToString()
            {
                return "{" + X + "," + Y + "}";
            }
        }

        public enum Sex
        {
            Male,
            Female
        }

        public class Person
        {
            public String Name { get; set; }
            public DateTime BirthDate { get; set; }
            public int Pets { get; set; }
            public Sex? Sex { get; set; }
            public Sex AttractedBy { get; set; }
            public DateTime? MarriedDate { get; set; }
            public Person Mother { get; set; }
            private Person Father;
            public bool IsMember;
            public Point? Coordinate { get; set; }
            public Point Point { get; set; }
            public int uc_Test1 { get; set; }   // Test of underscores.
            public int _ucTest2 { get; set; }
            public int ucTest3_;
            public int _ucTest4_;
            public int überÅker;     // Test of international characters
        }

        static int count1;
        static int count2;

        static void Main(string[] args)
        {

            Sex? sn = Sex.Female;

            int? i2 = (int?)sn;

            Sex s = Sex.Female;
            int i3 = (int)s;
            do
            {
                Console.WriteLine("Select comparison: ");
                Console.WriteLine("1=List<Person>.Sort((p1,p2) => String.Compare(p1.Name,p2.Name,...)");
                Console.WriteLine("2=List<Person>.Sort(ComparerBuilder<Person>.GetPropertyComparer(sortExpression, true)");
                Console.WriteLine("3=Reflection-Invoke-Based ");
                Console.WriteLine("4=List<Person>.Sort(sortExpression) using ComparerExtensions");
                Console.WriteLine("5=List<Person>.Sort using CreatePropertyComparer(sortExpression)");
                Console.WriteLine("6=List<Person>.Sort using.CreatePropertyComparerThroughEmit(sortExpression)");
                Console.WriteLine("7=List<Person>.AsQueryable().OrderBy(sortExpression)");
                Console.WriteLine("8=List<Person>.AsQueryable().OrderBy(p => p.Name)");
                Console.WriteLine("9=List<Person>.OrderBy(sortExpression)");
                Console.WriteLine("10=List<Person>.OrderBy(p => p.Name)");
                Console.WriteLine("11=CollectionViewSource.GetDefaultView(persons) sorting using SortDescription.");
                Console.WriteLine("12=CollectionViewSource.GetDefaultView(persons) sorting using CreateTypeComparer");
                Console.WriteLine("13=PersonDataTable.OrderBy(sortExpression)");
                Console.WriteLine("14=PersonDataTable.OrderBy(r => r.Name)");
                Console.WriteLine("15=PersonDataTable sorting using DataView.Sort=sortExpression");
                Console.WriteLine("16=ComparerBuilder<Person>.CreateTypeComparer(sortExpression)");
                Console.WriteLine("17=ComparerBuilder<Person>.CreateOrderByFunction(sortExpression)");
                Console.WriteLine("Enter choice : ");

                String compType = Console.ReadLine();

                String sortExpression;

                Console.Write("Sort expression: ");
                sortExpression = Console.ReadLine();

                Console.Write("Count in each iteration (will be repeated until at least 100000 items have been sorted.) : ");
                int count = int.Parse(Console.ReadLine());


                Stopwatch watch = new Stopwatch();

                int totCount = 0;
                IEnumerator enumToVerify = null;

                while (totCount < 100000)
                {

                    List<Person> persons = new List<Person>(count);
                    Random rnd = new Random(12232322);
                    for (int i = 0; i < count; i++)
                    {
                        Person p = new Person()
                        {
                            Name = i % 50 == 0 ? null : (rnd.Next(2) == 0 ? "Person" : "person") + rnd.Next(count),
                            BirthDate = DateTime.Now.AddDays(-rnd.Next(36500)),
                            Pets = rnd.Next(4),
                            Sex = rnd.Next(3) == 0 ? Sex.Male : rnd.Next(2) == 0 ? Sex.Female : new Sex?(),
                            AttractedBy = rnd.Next(2) == 0 ? Sex.Male : Sex.Female,
                            MarriedDate = rnd.Next(100) > 0 ? new DateTime?(DateTime.Now.AddDays(-rnd.Next(36500))) : new DateTime?(),
                            Mother = i > 10 && rnd.Next(10) < 3 ? persons[rnd.Next(i)] : null,
                            Coordinate = rnd.Next(100) < 50 ? new Point() { X = rnd.Next(1000), Y = rnd.Next(1000) } : new Point?()
                        };
                        persons.Add(p);
                    }
                    PersonDataSet.PersonsDataTable personTable = new PersonDataSet.PersonsDataTable();
                    if (compType == "13" || compType == "14" || compType == "15" || compType == "16" || compType == "17")
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Person person = persons[i];
                            PersonDataSet.PersonsRow row = personTable.AddPersonsRow(i, person.Name, person.BirthDate, person.Pets, person.MarriedDate.HasValue ? person.MarriedDate.Value : DateTime.Now);
                            if (person.MarriedDate.HasValue == false) { row.SetMarriedDateNull(); }
                        }
                    }

                    enumToVerify = null;
                    watch.Start();
                    Comparison<Person> compName;
                    switch (compType)
                    {
                        case "2":
                            compName = ComparerBuilder<Person>.GetPropertyComparison(sortExpression, true);
                            persons.Sort(compName);
                            break;
                        case "3":
                            Extensions.Extensions.Sort(persons, sortExpression);
                            break;
                        case "4":

                            ComparerExtensions.Sort(persons, sortExpression);
                            break;
                        case "5":
                            Comparison<Person> c = ComparerBuilder<Person>.CreatePropertyComparison(sortExpression, true);
                            persons.Sort(c);
                            break;
                        case "6":
                            Comparison<Person> c2 = ComparerBuilder<Person>.CreatePropertyComparisonThroughEmit(sortExpression, true);
                            persons.Sort(c2);
                            break;
                        case "7":
                            persons = new List<Person>(persons.AsQueryable().OrderBy(sortExpression));
                            break;
                        case "8":
                            persons = new List<Person>(persons.AsQueryable().OrderBy(p => p.Name));
                            break;
                        case "9":
                            persons = new List<Person>(persons.OrderBy(sortExpression));
                            break;
                        case "10":
                            persons = new List<Person>(persons.OrderBy(p => p.Name, StringComparer.CurrentCultureIgnoreCase));
                            break;
                        case "11":

                            ICollectionView personView = CollectionViewSource.GetDefaultView(persons);
                            personView.SortDescriptions.Add(new SortDescription(sortExpression, ListSortDirection.Ascending));
                            enumToVerify = personView.GetEnumerator();
                            break;
                        case "12":
                            ListCollectionView personView2 = (ListCollectionView)CollectionViewSource.GetDefaultView(persons);

                            personView2.CustomSort = (System.Collections.IComparer)ComparerBuilder<Person>.CreateTypeComparer(sortExpression);
                            enumToVerify = ((ICollectionView)personView2).GetEnumerator();
                            break;
                        case "13":
                            var lastRow = personTable.AsEnumerable().OrderBy(sortExpression).Last();
                            enumToVerify = personTable.AsEnumerable().OrderBy(sortExpression).GetEnumerator();
                            break;
                        case "14":
                            var lastRow2 = personTable.AsEnumerable().OrderBy(r => r.Field<String>("Name"), StringComparer.CurrentCultureIgnoreCase).ThenBy(r => r.Field<int>("Pets")).Last();
                            enumToVerify = personTable.AsEnumerable().OrderBy(r => r.Field<String>("Name"), StringComparer.CurrentCultureIgnoreCase).ThenBy(r => r.Field<int>("Pets")).GetEnumerator();
                            break;
                        case "15":
                            var view = personTable.DefaultView;
                            view.Sort = sortExpression;
                            enumToVerify = view.GetEnumerator();
                            break;
                        case "16":
                            IComparer<Person> comparer = ComparerBuilder<Person>.CreateTypeComparer(sortExpression);
                            persons = new List<Person>(persons.OrderBy(x => x, comparer));
                            break;
                        case "17":
                            OrderByFunction<Person> orderBy = ComparerBuilder<Person>.CreateOrderByFunction(sortExpression);
                            persons = new List<Person>(orderBy(persons));
                            break;
                        
                            
                        /*
                        case "19":
                            Phydeaux.Utilities.DynamicComparer<Person> dynComparer = new Phydeaux.Utilities.DynamicComparer<Person>(sortExpression);
                            persons.Sort(dynComparer.Comparer);
                            break;
                         */
                        case "20":
                            persons = new List<Person>(persons.OrderBy(p => p.AttractedBy));
                            break;
                        case "21":
                            persons = new List<Person>(persons.OrderBy(p => (int)p.AttractedBy));
                            break;
                        case "22":
                            persons = new List<Person>(persons.OrderBy(p => p.Sex,ExtendedComparer<Sex?>.Default));
                            
                            break;
                        default:
                            compName = (Person p1, Person p2) => String.Compare(p1.Name, p2.Name, StringComparison.CurrentCultureIgnoreCase);
                            //compName = (Person p1, Person p2) => Nullable.Compare(p1.Coordinate, p2.Coordinate);
                            //compName = (Person p1, Person p2) => p1.Sex.CompareTo(p2.Sex);
                            persons.Sort(compName);
                            break;
                    }
                    watch.Stop();
                    if (enumToVerify == null)
                    {
                        enumToVerify = persons.GetEnumerator();
                    }

                    totCount += count;

                }
                watch.Stop();
                Console.WriteLine("Time to sort {0} persons {1} times by {3}: {2} ms", count, totCount / count, watch.ElapsedMilliseconds, sortExpression);
                Console.WriteLine("Press ENTER to enumerate results. Enter q to quit enumeration.");
                while (Console.ReadLine() != "q")
                {
                    int i = 0;
                    while (i < 10 && enumToVerify.MoveNext())
                    {
                        if (enumToVerify.Current is Person)
                        {
                            Person p = (Person)enumToVerify.Current;
                            Console.WriteLine("{0} {1} {2} {3} {4} ({5})", p.Name, p.Sex, p.BirthDate, p.MarriedDate, p.Coordinate, p.Mother == null ? "none" : p.Mother.Name);
                            i++;
                        }
                        else if (enumToVerify.Current is DataRow)
                        {
                            DataRow r = (DataRow)enumToVerify.Current;
                            Console.WriteLine("{0} {1} {2} {3}", r["Name"], r["Pets"], r["BirthDate"], r.Field<DateTime?>("MarriedDate"));
                            i++;
                        }
                        else if (enumToVerify.Current is DataRowView)
                        {
                            DataRow r = ((DataRowView)enumToVerify.Current).Row;
                            Console.WriteLine("{0} {1} {2} {3}", r["Name"], r["Pets"], r["BirthDate"], r.Field<DateTime?>("MarriedDate"));
                            i++;
                        }
                    }
                    Console.WriteLine("Press ENTER to show more results. Enter q to quit enumeration.");
                }
                Console.WriteLine("Press ENTER to go to main menu. Enter q to quit program. ");
            } while (Console.ReadLine() != "q");
        }
    }
}
